package 回溯;

import org.junit.Test;

/**
 * @description: 八皇后问题, 8*8的棋盘, 共有多少种放法?
 * @author: shuai.chen@shuyun.com
 * @date: 2023/2/7 4:22 PM
 */
public class EightQueen {

    @Test
    public void demo01(){
        cal8queens(0);
        System.out.println("一共 " + total + " 种放法");
    }

    //region 参考1
    // 为啥用1维数组? 第一回合走完后, 下一回合数据存哪里?
    int rowAndColumn = 8;
    int[] result = new int[rowAndColumn];//全局或成员变量,下标表示行,值表示queen存储在哪一列
    int total = 0;
    public void cal8queens(int row) { // 调用方式：cal8queens(0);
        if (row == rowAndColumn) { // 8个棋子都放置好了，打印结果
            printQueens(result);
            return; // 8行棋子都放好了，已经没法再往下递归了，所以就return
        }
        for (int column = 0; column < rowAndColumn; ++column) { // 每一行都有8种放法
            if (isOk(row, column)) { // 有些放法不满足要求
                result[row] = column; // 第row行的棋子放到了column列
                cal8queens(row+1); // 考察下一行
            }
        }
    }

    private boolean isOk(int row, int column) {//判断row行column列放置是否合适
        int leftup = column - 1, rightup = column + 1;
        for (int i = row-1; i >= 0; --i) { // 逐行往上考察每一行
            if (result[i] == column) return false; // 第i行的column列有棋子吗？
            if (leftup >= 0) { // 考察左上对角线：第i行leftup列有棋子吗？
                if (result[i] == leftup) return false;
            }
            if (rightup < rowAndColumn) { // 考察右上对角线：第i行rightup列有棋子吗？
                if (result[i] == rightup) return false;
            }
            --leftup; ++rightup;
        }
        return true;
    }

    private void printQueens(int[] result) { // 打印出一个二维矩阵
        total++;
        for (int row = 0; row < rowAndColumn; ++row) {
            for (int column = 0; column < rowAndColumn; ++column) {
                if (result[row] == column) System.out.print("Q ");
                else System.out.print("* ");
            }
            System.out.println();
        }
        System.out.println();
    }
    //endregion

    //region 自己写
    public void put2(int row){
        // 终止条件
        if (row == 8) {
            print2();
            return;
        }
        // 如果满足条件就往第row行放Q
        for (int column = 0; column < 8; column++) {
            if(isOk2(row, column)) {
                result[row] = column;
                // 继续下一行
                put2(row++);
            }
        }
    }

    private void print2() {
    }

    // 当前是否满足：横 、 竖 、对角线
    public boolean isOk2(int row, int column) {

        return true;
    }
    //endregion


}
